﻿
#include <stdio.h>

//int main()
//{
//	int n = 0;
//	int* p = &n;//p为指针变量
//	*p = 20;//*为解引用操作符
//	printf("%d", n);
//
//	return 0;
//}

//指针变量的大小
//int main()
//{
//	int n = 0;
//	int* p = &n;
//	char* c = &n;
//	short* s = &n;
//	void* v = &n;
//	printf("%zd ", sizeof(p));
//	printf("%zd ", sizeof(c));
//	printf("%zd ", sizeof(s));//sizeof用%zd打印
//	printf("%zd ", sizeof(v));//指针变量的大小相同，在32位下为4字节，在64下为8字节
//
//	return 0;
//}


//指针变量类型的意义
//int main()
//{
//	int n = 0x11223344;
//	int* pi = &n;
//	*pi = 0;//会调取4个字节进行改变
//
//	return 0;
//}
//
//int main()
//{
//	int n = 0x11223344;
//	char* pi = (char*) & n;
//	*pi = 0;//会调取1个字节进行改变
//
//	return 0;
//}
//char* 的指针解引⽤就只能访问⼀个字节，⽽int*的指针的解引⽤就能访问四个字节

//
//int main()
//{
//	int n = 0x11223344;
//	int* pi = &n;
//	*pi = 0;
//	int* c = &pi;
//	printf("%p", c);
//
//	return 0;
//}

//指针+-整数
//int main()
//{
//	int n = 0;
//	int* p = &n;
//	printf("%p\n", p);
//	printf("%p\n", p+1);
//	printf("%p\n", p-1);
//	//000000AEC019FBE4
//	//000000AEC019FBE8
//	//000000AEC019FBE0
//
//	return 0;
//}

//int main()
//{
//	char n = '0';
//	char* p = &n;
//	printf("%p\n", p);
//	printf("%p\n", p + 1);
//	printf("%p\n", p - 1);
//	//000000B87E70FA34
//	//000000B87E70FA35
//	//000000B87E70FA33
//
//
//	return 0;
//}

//const修饰指针
//int main()
//{
//	const int b = 0;//无法修改b的值，但用指针可以
//	int* p = &b;
//	*p = 20;
//	printf("%d", b);//20
//
//	return 0;
//}

//const修饰指针变量
//test1()
//{
//	int n = 0;
//	int m = 0;
//	const int* p = &n;
//	*p = 10;//const放在*左边，*p固定，不能随意更改n的值
//	p = &m;
//}
//test2()
//{
//	int n = 0;
//	int m = 0;
//	int*const p = &n;
//	*p = 10;
//	p = &m;//const放在*右边，p固定，不能随意改变指针变量所存地址
//}
//test3()
//{
//	int n = 0;
//	int m = 0;
//	const int*const p = &n;//const放在*的两边，当然都不可随意更改
//	*p = 10;
//	p = &m;
//}
//int main()
//{
//	test1();
//	test2();
//	teat3();
//
//	return 0;
//}

//指针运算
//1.指针+-整数
//2.指针-指针
//表示在同一空间中两地址之间隔的元素个数，有符号（分正负）
//int main()
//{
//	int arr[10] = { 0 };
//	int sz = sizeof arr / sizeof arr[0];
//	int* p = &arr;
//	printf("%d", p - (p + sz - 1));
//
//	return 0;
//}

//~~~~~~~int my_strlen(char* s)
//{
//	char* p = s;
//	while (*p != '\0')
//		p++;//指针+整数
//	return p - s;
//}
//int main()
//{
//	printf("%d\n", my_strlen("abc"));//当传递字符串时，实际上是传递了字符串的首地址，即指向字符串第一个字符的指针，和数组类似~不用加&
//	return 0;
//}


//野指针
//1.未初始化指针变量
//int main()
//{
//	int* p;
//
//	return 0;
//}
//2.指针越界访问
//int main()
//{
//	int arr[10] = {0};
//	int* p = &arr;
//	for (int n = 0;n < 11; n++)
//	{
//		printf("%d", *(arr + n));//0000000000-858993460
//	}
//
//	return 0;
//}
//
//int main()
//{
//	int arr[10] = { 0 };
//	int* p = &arr;
//	for (int n = 0; n < 10; n++)
//	{
//		printf("%d", *(arr + n));//0000000000
//	}
//
//	return 0;
//}
//3.指针指向的空间释放
//int* test()
//{
//	int n = 0;
//	int* p = &n;
//	return p;//n为局部变量，当跳出test函数范围，失效，其地址为野指针
//}
//int main()
//{
//	int* s = test();
//	printf("%p", s);
//
//	return 0;
//}


//如何规避野指针
//1.指针初始化
//int * p = NULL;//NULL是C语⾔中定义的⼀个标识符常量，值是0，0也是地址，这个地址是⽆法使⽤的，读写该地址会报错
//2.小心指针越界
///////使用指针前，要判断是不是NULL,如果不是才可以使用
//if(p!=NULL)//判断
//3.不要返回局部变量的指针

//assert断言
//头文件<assert.h>
//assert() 宏接受⼀个表达式作为参数。如果该表达式为真（返回值⾮零），任何作⽤，程序继续运⾏。如果该表达式为假（返回值为零
//assert()不会产⽣assert()就会报错，在标准错误derr中写⼀条错误信息，显⽰没有通过的表达式，以及包含这个表达式的⽂件名和⾏号

//#define NDEBUG///////将此放在头文件之前，可关闭assert断言功能
//#include <assert.h>


//传值调用和传址调用
//形参也单独保存，只通过操控形参无法真实操控实参，可用传址调用，若像加法函数可用传值调用，因为其结果对于形参和实参来说相同~